package org.hs.phd.common.improc.traversal;

import static com.googlecode.javacv.cpp.opencv_core.cvCopy;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import com.googlecode.javacv.cpp.opencv_core;
import com.googlecode.javacv.cpp.opencv_core.IplImage;

public class MaskBasedRGBImagePolygonalTraverser implements RGBImagePixelTraverser {

	private final Polygon polygon;

	public MaskBasedRGBImagePolygonalTraverser(Polygon polygon) {
		this.polygon = polygon;
	}

	@Override
	public void traversePixels(IplImage frame, RGBImagePixelProcessor processor) {
		assert frame.getBufferedImageType() == BufferedImage.TYPE_3BYTE_BGR;
		
		Rectangle rect = polygon.getBounds().intersection(new Rectangle(0,0, frame.width(), frame.height()));
		
		int[] rgbs = getImageRGBs(frame, rect);
		int[] mask = getMaskArray();

		
		for(int j = 0; j < rect.height; j++){
			for(int i = 0; i < rect.width; i++){

				int baseIndex = i + j*rect.width;
				
				if((mask[baseIndex] & 0xFF) != 0 ){
				
					int rgb = rgbs[ baseIndex ];
					int nB = rgb & 0xFF;
					int nG = (rgb >> 8) & 0xFF;
					int nR = (rgb >> 16) & 0xFF;
					
					processor.processPixel(i + rect.x, j + rect.y, nR, nG, nB);
				}
			}
		}
	}

	private int[] getMaskArray() {
		Rectangle rect = polygon.getBounds();
		
		BufferedImage maskImage = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_BYTE_BINARY); 
		
		Graphics2D g2 = maskImage.createGraphics();		
		g2.translate(-rect.x, -rect.y);
		g2.setColor(Color.BLACK);
		g2.fillRect(rect.x, rect.y, rect.width, rect.height);
		g2.setColor(Color.WHITE);
		g2.fillPolygon(polygon);
		g2.dispose();
		
		int[] rgbs = new int[rect.height*rect.width];
		maskImage.getRGB(0, 0, rect.width, rect.height, rgbs, 0, rect.width);
		return rgbs;
	}

	private int[] getImageRGBs(IplImage frame, Rectangle rect) {
		opencv_core.cvSetImageROI(frame, opencv_core.cvRect(rect.x, rect.y, rect.width, rect.height));
		IplImage croppedImage = opencv_core.cvCreateImage(opencv_core.cvSize(rect.width, rect.height), frame.depth(), frame.nChannels());
		cvCopy(frame, croppedImage);
		opencv_core.cvResetImageROI(frame);

		BufferedImage bufferedImage = croppedImage.getBufferedImage();
		int[] rgbs = new int[rect.height*rect.width];
		bufferedImage.getRGB(0, 0, rect.width, rect.height, rgbs, 0, rect.width);

		opencv_core.cvReleaseImage(croppedImage);
		return rgbs;
	}

}
